package com.darkduck.fcap;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.ActivityNotFoundException;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Parcelable;
import android.provider.ContactsContract;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import com.darkduck.fcap.camera.CameraManager;

public class CaptureActivity extends Activity implements SurfaceHolder.Callback, OnClickListener {
    
    private static final String TAG = CaptureActivity.class.getSimpleName();
    private static final String SD_DIR = "/sdcard/DCIM/FaceCapture/";
    private static final String SUFFIX_FILE = ".jpg";
    private static final String TEMP_FILENAME = "TEMP0323857438xccvfd";
    private static final String GOOGLE_IMAGES_URL_PREFIX = "http://www.google.com/images";
    
    private static final int SAVE_PHOTO_DIALOG_ID = 0;
    private static final int ABOUT_DIALOG_ID = 1;
    private static final int WEB_SEARCH_TIP_ID = 2;

    private boolean hasSurface;
    private CaptureActivityHandler handler;    
    private TextView mPomptView;
    private View mAdView;
    private ViewGroup mResultView;
    private BmpCheckItem[] mBmpCheckArray;
    private int mClickItem;  
    private BeepManager beepManager;
    private boolean isResultVisible;
    
    
    private class BmpCheckItem {
        private Bitmap mBmp;
        private String mName;
        
        public BmpCheckItem(Bitmap bmp, String name) {
            mBmp = bmp;
            mName = name;

        }

        public Bitmap getBitmap() {
            return mBmp;
        }
        
        public String getName() {
            return mName;
        }
        
        public void setName(String name) {
            mName = name;
        }
        

        
    }
    
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        Window window = getWindow();
        window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        setContentView(R.layout.capture);        
        
        CameraManager.init(getApplication());
        mPomptView = (TextView) findViewById(R.id.prompt_view);
        mResultView = (ViewGroup) findViewById(R.id.result_view);
        //for admob AD
        mAdView = (View) findViewById(R.id.domobAD_view);
        //for casee AD
        //mAdView = (View) findViewById(R.id.caseeAdView);
        
        ViewGroup buttonView = (ViewGroup) findViewById(R.id.result_button_view);
        buttonView.requestFocus();
        for (int i = 0; i < buttonView.getChildCount(); i++) {
            Button btn = (Button) buttonView.getChildAt(i);
            btn.setOnClickListener(this);
        }
        hasSurface = false;

        isResultVisible = false;
        mBmpCheckArray = null;
        mClickItem = 0;
        beepManager = new BeepManager(this);

    }
    
    @Override
    protected void onResume() {
        super.onResume();
      //check whether SD exists
        if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            Toast.makeText(CaptureActivity.this, R.string.toast_sd_check, Toast.LENGTH_LONG).show();
        }
        SurfaceView surfaceView = (SurfaceView) findViewById(R.id.preview_view);
        SurfaceHolder surfaceHolder = surfaceView.getHolder();
        if (hasSurface) {
            // The activity was paused but not stopped, so the surface still exists. Therefore
            // surfaceCreated() won't be called, so init the camera here.
            initCamera(surfaceHolder);
          } else {
            // Install the callback and wait for surfaceCreated() to init the camera.
            surfaceHolder.addCallback(this);
            surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
          }
        beepManager.updatePrefs();
    }
    
    @Override
    protected void onPause() {
        if (handler != null) {
            handler.quitSynchronously();
            handler = null;
          }
        CameraManager.get().closeDriver();
        super.onPause();
        
    }
    
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        switch (keyCode) {
            case KeyEvent.KEYCODE_BACK:
                if (mResultView.getVisibility() == View.VISIBLE) {
                    resetViewVisibility();
                    if (handler != null) {
                        handler.sendEmptyMessage(R.id.restart_preview);
                    }              
                    resetGlobalResource();
                    cleanTempFile();
                }
                else {
                    finish(); 
                }                
                return true;
            
            case KeyEvent.KEYCODE_CAMERA:                
                CameraManager.get().setFrontLightEnable(true);
                return true;                
            
            default:
                return super.onKeyDown(keyCode, event);           
         
        }
    }
    
    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        switch (keyCode) {
            
            case KeyEvent.KEYCODE_CAMERA:
                CameraManager.get().setFrontLightEnable(false);
                return true;
        }
        return super.onKeyUp(keyCode, event);
    }
    
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        // TODO Auto-generated method stub
        
    }
    
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        if (!hasSurface) {
            hasSurface = true;
            initCamera(holder);
          }        
    }
    
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        hasSurface = false;        
    }
    
    
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.save_photo_button:                
                showDialog(SAVE_PHOTO_DIALOG_ID);                             
                break;
                
            case R.id.share_button:
                //save first
                String fileName = null;
                if (TextUtils.isEmpty(mBmpCheckArray[mClickItem].getName())) {
                    fileName = TEMP_FILENAME + SUFFIX_FILE;
                    SavePhotoTask savePhotoTask = new SavePhotoTask();
                    savePhotoTask.execute(mBmpCheckArray[mClickItem], fileName);
                }
                else {
                    fileName = mBmpCheckArray[mClickItem].getName();
                }                
                
                Uri uri = Uri.parse("file://" + SD_DIR + fileName);
                Intent intent = new Intent(Intent.ACTION_SEND);
                intent.putExtra(Intent.EXTRA_STREAM, uri);
                intent.setType("image/jpeg");
                launchIntent(intent);
                break;
                
           /* case R.id.save_and_set_contact_photo_button:
                if (TextUtils.isEmpty(mBmpCheckArray[mClickItem].getName())) {
                    fileName = "CONTACT_PHOTO" + System.currentTimeMillis() + SUFFIX_FILE;
                    SavePhotoTask savePhotoTask = new SavePhotoTask();
                    savePhotoTask.execute(mBmpCheckArray[mClickItem], fileName);
                }
                
                Intent i = new Intent(Intent.ACTION_VIEW);
                i.setData(ContactsContract.Contacts.CONTENT_URI);
                startActivity(i);
                break;*/
                
            case R.id.web_search_button:
                // if save, search by file name
                if (TextUtils.isEmpty(mBmpCheckArray[mClickItem].getName())) {
                    showDialog(WEB_SEARCH_TIP_ID); 
                } 
                //if not, show tip dialog
                else {
                    webSearch(mBmpCheckArray[mClickItem].getName());
                }                            
                break;
                
            case R.id.cancel_button:
                resetViewVisibility();
                if (handler != null) {
                    handler.sendEmptyMessage(R.id.restart_preview);
                }              
                resetGlobalResource();
                cleanTempFile();
                break;
                
            default:
                break;
        }
    }   

    @Override
    protected Dialog onCreateDialog(int id) {
        Dialog dialog = null;
        switch (id) {
            case SAVE_PHOTO_DIALOG_ID:                
                dialog = createSavePhotoDialog();
            break;
            case ABOUT_DIALOG_ID:
                dialog = createAboutDialog();
                break;
            case WEB_SEARCH_TIP_ID:
                dialog = createWebSearchTipDialog();
                break;
            default:
                return super.onCreateDialog(id);
        }
        return dialog;
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.preview_context_menu, menu);
        return true;
    }
    
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.about_item:
                showDialog(ABOUT_DIALOG_ID);
                return true;

            case R.id.setting_item:
                Intent intent = new Intent(Intent.ACTION_VIEW);
                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
                intent.setClassName(this, PreferencesActivity.class.getName());
                startActivity(intent);
                return true;
                
            case R.id.help_item:
                Intent i = new Intent(Intent.ACTION_VIEW);
                i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
                i.setClassName(this, HelpActivity.class.getName());
                startActivity(i);
                return true;
                
            case R.id.gallery_item:
                Intent ii = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.INTERNAL_CONTENT_URI);          
                startActivity(ii);
                return true;
                
            case R.id.contact_item:
                Intent contactIntent = new Intent(Intent.ACTION_VIEW);
                contactIntent.setData(ContactsContract.Contacts.CONTENT_URI);
                launchIntent(contactIntent);
                return true;

            default:
                return super.onOptionsItemSelected(item);
        }
    }    
    
    public boolean getResultVisibleState() {
        return isResultVisible;
    }
    
    private BmpCheckItem[] createCheckList(ArrayList<Parcelable> list) {
        mBmpCheckArray = null;
        mBmpCheckArray = new BmpCheckItem[list.size()];
        for (int i = 0; i < list.size(); i++) {
            mBmpCheckArray[i] = new BmpCheckItem((Bitmap)list.get(i), null);
        }
        
        return mBmpCheckArray;
    }

    
    
    private void cleanTempFile() {
        File file = new File(SD_DIR, TEMP_FILENAME + SUFFIX_FILE);
        if (file.exists()) {
            file.delete();
        }        
    }
    private void initCamera(SurfaceHolder surfaceHolder) {
        try {            
            CameraManager.get().openDriver(surfaceHolder);
            // Creating the handler starts the preview, which can also throw a
            // RuntimeException.
            if (handler == null) {
                handler = new CaptureActivityHandler(this);
            }
        } catch (IOException ioe) {
            Log.w(TAG, ioe);
            displayFrameworkBugMessageAndExit();
        } catch (RuntimeException e) {
            Log.w(TAG, "Unexpected error initializating camera", e);
            displayFrameworkBugMessageAndExit();
        }
    }

    private Dialog createWebSearchTipDialog() {
        LayoutInflater inflater = LayoutInflater.from(this);
        final View view = inflater.inflate(R.layout.save_photo_dialog, null);
        
        final EditText tip = (EditText) view.findViewById(R.id.edit_photo_name);
        
        return new AlertDialog.Builder(CaptureActivity.this).setTitle(R.string.dialog_title_web_search)
                .setView(view)
                .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {

                    @Override
                    public void onClick(DialogInterface dialog, int which) {          
                       
                        String searchTip = tip.getText().toString();                       
                        webSearch(searchTip);
                        
                        dialog.cancel();                        
                    }                    
                }).setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {

                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        
                        dialog.cancel();
                    }
                }).create();
    }
  
    private Dialog createSavePhotoDialog() {
        LayoutInflater inflater = LayoutInflater.from(this);
        final View view = inflater.inflate(R.layout.save_photo_dialog, null);
        
        final EditText name = (EditText) view.findViewById(R.id.edit_photo_name);
        
        return new AlertDialog.Builder(CaptureActivity.this).setTitle(R.string.msg_set_photo_name)
                .setView(view)
                .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {

                    @Override
                    public void onClick(DialogInterface dialog, int which) {          
                       
                        String filename = name.getText().toString() + SUFFIX_FILE;                        
                        
                        SavePhotoTask savePhotoTask = new SavePhotoTask();
                        savePhotoTask.execute(mBmpCheckArray[mClickItem], filename);
                        
                        dialog.cancel();                        
                    }                    
                }).setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {

                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        
                        dialog.cancel();
                    }
                }).create();
    }
    
    private Dialog createAboutDialog() { 
        String content = getAboutContent();
        return new AlertDialog.Builder(this)
        .setTitle(R.string.about_title)
        .setMessage(content == null ? getResources().getString(R.string.about_content) : content)
        .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
            
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.cancel();
                
            }
        })
        .create(); 
    }
    
    private String getAboutContent() {
        String content = null;
        try {
        PackageInfo pinfo = getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_CONFIGURATIONS);
        String versionName = pinfo.versionName;
        
        content = getResources().getString(R.string.version) + ": " + versionName + "\n" 
                + getResources().getString(R.string.email);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return content;
    }
    
    private void displayFrameworkBugMessageAndExit() {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setIcon(R.drawable.alert_dialog_icon);
        builder.setTitle(getString(R.string.app_name));
        builder.setMessage(getString(R.string.msg_camera_framework_bug));
        builder.setPositiveButton(R.string.ok, new FinishListener(this));
        builder.setOnCancelListener(new FinishListener(this));
        builder.show();
    }    
    
    private boolean changeFileName(String name, String newName) {
        File file = new File(SD_DIR, name);
        if (file.exists()) {
            return file.renameTo(new File(SD_DIR, newName));
        }
        return false;
    }

    private void resetGlobalResource() {
        mClickItem = 0;
       
        if (mBmpCheckArray == null) return;
        for (int i = 0; i < mBmpCheckArray.length; i++) {
            Bitmap bmp = mBmpCheckArray[i].getBitmap();
            bmp.recycle();
        }
        mBmpCheckArray = null;                
    }
    
    private void resetViewVisibility() {
        mPomptView.setVisibility(View.VISIBLE);
        mAdView.setVisibility(View.VISIBLE);
        mResultView.setVisibility(View.GONE);
        isResultVisible = false;
    }
    
    private void setResultViewVisible() {
        mPomptView.setVisibility(View.GONE);
        mAdView.setVisibility(View.INVISIBLE);
        isResultVisible = true;
        mResultView.setVisibility(View.VISIBLE);
    }   
    
    private void webSearch(String query) {
        String url = GOOGLE_IMAGES_URL_PREFIX + "?q=" + query;
        Intent searchIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));        
        launchIntent(searchIntent);
      }
    
    private void launchIntent(Intent intent) {
        if (intent != null) {
            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
            Log.d(TAG, "Launching intent: " + intent + " with extras: " + intent.getExtras());
            try {
                startActivity(intent);
            } catch (ActivityNotFoundException e) {
                AlertDialog.Builder builder = new AlertDialog.Builder(this);
                builder.setTitle(R.string.app_name);
                builder.setMessage(R.string.msg_intent_failed);
                builder.setPositiveButton(R.string.ok, null);
                builder.show();
            }
        }
    }
    
    public Handler getHandler() {
        return handler;
      }   
    

    public void handleDecode(Object obj, ArrayList<Parcelable> list) {
        mBmpCheckArray = createCheckList(list);
       
        ImageAdapter adapter = new ImageAdapter(this, list);
        adapter.createReflectedImages();
        GalleryFlow galleryFlow = (GalleryFlow) this.findViewById(R.id.gallery);  
        galleryFlow.setFadingEdgeLength(0);  
        galleryFlow.setSpacing(50); //图片之间的间距  
        galleryFlow.setAdapter(adapter);

        galleryFlow.setOnItemClickListener(new OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {                
                mClickItem = position;
            }
        });
        
        beepManager.playBeepSoundAndVibrate();
        
        setResultViewVisible();
        
    }   
    
    private class SavePhotoTask extends AsyncTask<Object, Void, Integer> {
        private ProgressDialog mProgressDialog;
        private static final int SAVE_SUCCESS = 0;
        private static final int SAVE_FAIL = 1;
        private static final int FILE_EXIST = 2;
        private static final int EMPTY_INPUT = 3;
        private static final int CHANGE_NAME_SUCCESS = 4;
        private static final int CHANGE_NAME_FAIL = 5;
        private static final int NONE = 6;
        
        
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            mProgressDialog = new ProgressDialog(CaptureActivity.this);
            mProgressDialog.show();
            mProgressDialog.setOnCancelListener(new OnCancelListener() {

                @Override
                public void onCancel(DialogInterface dialog) {
                    dialog.cancel();
                }
            });
        }

        @Override
        protected Integer doInBackground(Object... params) {
            BmpCheckItem btp = (BmpCheckItem)params[0];
            String fileName = (String)params[1];    
            Log.i(TAG, "filename:"+fileName+ ",bitmap name:"+btp.getName());
            //empty name
            if (fileName.equals(SUFFIX_FILE)) {
                return EMPTY_INPUT;
            }
            
            
            //change name
            if (!TextUtils.isEmpty(btp.getName()) && !fileName.equals(btp.getName())) {
                if (changeFileName(btp.getName(), fileName))
                    return CHANGE_NAME_SUCCESS;
                return CHANGE_NAME_FAIL;
            }
            
            if (TextUtils.isEmpty(btp.getName())) {
                //file have exist
                File file = new File(SD_DIR, fileName);                    
                if (file.exists()) {
                    return FILE_EXIST;
                }
                
                //save
                if (saveBitmap(btp.getBitmap(), fileName)) {
                    btp.setName(fileName);
                    return SAVE_SUCCESS;
                }
                return SAVE_FAIL;
            }         
            
            return NONE;
                  
        }

        @Override
        protected void onPostExecute(Integer result) {
            mProgressDialog.dismiss();
           
            switch (result) {
                case SAVE_SUCCESS:
                    Toast.makeText(CaptureActivity.this, R.string.msg_save_success_prompt, Toast.LENGTH_SHORT).show();
                    break;
                case SAVE_FAIL:
                    Toast.makeText(CaptureActivity.this, R.string.msg_save_false_protmpt, Toast.LENGTH_SHORT).show();
                    break;
                case EMPTY_INPUT:
                    Toast.makeText(CaptureActivity.this, R.string.msg_empty_input, Toast.LENGTH_SHORT).show();
                    break;
                case CHANGE_NAME_SUCCESS:
                    Toast.makeText(CaptureActivity.this, R.string.msg_change_name_success, Toast.LENGTH_SHORT).show();
                    break;
                case CHANGE_NAME_FAIL:
                    Toast.makeText(CaptureActivity.this, R.string.msg_change_name_fail, Toast.LENGTH_SHORT).show();
                    break;
                case FILE_EXIST:
                    Toast.makeText(CaptureActivity.this, R.string.msg_file_exist, Toast.LENGTH_SHORT).show();
                    break;
                default:
                    Log.e(TAG, "not expected return value SavePhotoTask");
                    break;
            }

        }
        
        
        private boolean saveBitmap(Bitmap btp, String filename) {
            OutputStream out = null;
            
            if (btp == null) {
                Log.e(TAG, "bitmap is null");
                return false;
            }

            File dir = new File(SD_DIR);
            if (!dir.exists()) {
                dir.mkdirs();
            }
            try {
                File file = new File(SD_DIR, filename);

                out = new FileOutputStream(file);
                if (!btp.compress(CompressFormat.JPEG, 80, out)) {
                    Log.e(TAG, "bitmap compress error");
                    return false;
                }
                out.flush();
                out.close();
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }

            return true;
        }
       

    }
    
    
    
}